package jmine.tec.hydra;

import java.io.InputStream;
import java.util.Map;

import jmine.tec.hydra.api.CallActivationAction;
import jmine.tec.hydra.api.EncodeMessageAction;
import jmine.tec.hydra.api.HydraAction;
import jmine.tec.hydra.api.HydraRequest;
import jmine.tec.hydra.api.HydraSpecification;
import jmine.tec.hydra.api.ReceiveMessageAction;
import jmine.tec.hydra.domain.HydraSystem;
import jmine.tec.hydra.domain.enumx.HydraRequestType;

/**
 * Handler de todos os requests do Hydra.
 * 
 * @author marco.vieira
 */
public class RequestHandler {

    private final HydraController controller;

    /**
     * @param controller instancia de {@link HydraController}.
     */
    public RequestHandler(HydraController controller) {
        this.controller = controller;
    }

    /**
     * Executa o envio
     * 
     * @param source source
     * @param activation activation
     * @return HydraRequest
     */
    public HydraRequest send(Object source, String activation) {
        if (source == null) {
            throw new NullPointerException("Source must not be null!");
        }
        if (activation == null) {
            throw new NullPointerException("Activation must not be null!");
        }
        CallActivationAction action = this.controller.getProvider().createAction(CallActivationAction.class);
        action.prepare(source, activation);
        return this.executeAction(HydraRequestType.SEND, action);
    }

    /**
     * Executa o envio
     * 
     * @param source source
     * @param specification specification
     * @return HydraRequest
     */
    public HydraRequest send(Object source, HydraSpecification specification) {
        if (source == null) {
            throw new NullPointerException("Source must not be null!");
        }
        if (specification == null) {
            throw new NullPointerException("Specification must not be null!");
        }
        EncodeMessageAction action = this.controller.getProvider().createAction(EncodeMessageAction.class);
        action.prepare(source);
        return this.executeAction(HydraRequestType.SEND, action, specification);
    }

    /**
     * Executa o recebimento de uma mensagem
     * 
     * @param system system
     * @param input input
     * @param messageProperties messageProperties
     * @return HydraRequest
     */
    public HydraRequest receive(HydraSystem system, InputStream input, Map<String, String> messageProperties) {
        if (system == null) {
            throw new NullPointerException("System must not be null!");
        }
        if (input == null) {
            throw new NullPointerException("MessageInputStream must not be null!");
        }
        ReceiveMessageAction action = this.controller.getProvider().createAction(ReceiveMessageAction.class);
        action.prepare(system, input, messageProperties);
        return this.executeAction(HydraRequestType.RECEIVE, action);
    }

    /**
     * Executa uma action
     * 
     * @param requestType requestType
     * @param action action
     * @return HydraRequest
     */
    private HydraRequest executeAction(HydraRequestType requestType, HydraAction action) {
        HydraRequest request = this.controller.getProvider().createRequest(requestType);
        return request.execute(action);
    }

    /**
     * Executa uma action
     * 
     * @param requestType requestType
     * @param action action
     * @param specification specification
     * @return HydraRequest
     */
    private HydraRequest executeAction(HydraRequestType requestType, HydraAction action, HydraSpecification specification) {
        HydraRequest request = this.controller.getProvider().createRequest(requestType, specification);
        return request.execute(action);
    }
}
